<!-- 自动聚焦贴键盘 -->
<template>
  <view
    class="editor-container"
    :class="{ 'editor-container-retracted': retracted }"
  >
    <view class="editor-box" :style="{ bottom: `${editorBottom}px` }">
      <view class="edit-area">
        <view class="edit-body">
          <editor
            id="seeker-editor"
            :placeholder="placeholder"
            showImgSize
            showImgToolbar
            showImgResize
            @statuschange="onStatusChange"
            :read-only="readOnly"
            @ready="onEditorReady"
            @focus="bindFocus"
            @blur="bindBlur"
            @input="bindInput"
            :focus="focus"
          ></editor>
        </view>
      </view>
      <view class="edit-bar">
        <view
          v-for="item in barListActive"
          :key="item.id"
          @click="handleBarClick(item)"
          :style="item.style"
        >
          <template v-if="item.text">
            <span :style="{ color: item.activeColor }">
              {{ item.text }}
            </span>
          </template>
          <template v-else>
            <img :src="item.activeIcon" />
          </template>
        </view>
      </view>
    </view>
    <view class="editor-mask" @click="handleClickMask"></view>
  </view>
</template>

<script>
import component from '../components.js'
export default {
  mixins: [component],
  props: {
    // 富文本值
    value: {
      type: String,
      default: null,
    },
  },
  data() {
    const isIos = uni.getSystemInfoSync().platform.includes('ios')
    return {
      isIos,
      editorCtx: null, // 编辑器实例
      focus: false, // 编辑器光标聚焦
      retracted: true, // 编辑器收起
      readOnly: false, // 只读
      formats: {}, // 当前选中的格式化样式
      inputFakeText: '', // 输入框展示内容
      placeholder: '输入你的内容',
      keyHei: 0, // 键盘高度
      editorBottom: undefined, // 底部距离，用于贴近键盘
      barList: [
        // 操作栏
        {
          id: 0,
          name: '标题',
          text: 'Hh',
          color: '#333333',
          colorAct: '#6B5AF7',
          format: {
            key: 'header',
            val: 3,
          },
        },
        {
          id: 1,
          name: '加粗',
          icon: '/static/edit_icon/overstriking.png',
          iconAct: '/static/edit_icon/overstriking_act.png',
          format: {
            key: 'bold',
            // #ifdef APP-PLUS || H5
            val: true,
            // #endif
            // #ifdef MP
            val: 'strong',
            // #endif
          },
        },
        {
          id: 2,
          name: '图片',
          icon:
            'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-16774c93-6874-4a5e-97e7-f451eac9da38/0fb58f74-b2bb-4d31-9899-35d4b9168db5.png',
        },
        {
          id: 3,
          name: '撤销',
          icon: '/static/edit_icon/last_act.png',
        },
        {
          id: 4,
          name: '重做',
          icon: '/static/edit_icon/next_act.png',
        },
        {
          id: 5,
          name: '发送',
          text: '发送',
          style: {
            color: 'white',
            fontSize: '24rpx',
            fontWeight: '500',
            backgroundImage:
              'linear-gradient( 76.3deg,  rgba(44,62,78,1) 12.6%, rgba(69,103,131,1) 82.8% )',
            borderRadius: '20rpx',
            padding: '6rpx 20rpx',
          },
        },
      ],
    }
  },
  mounted() {
    uni.onKeyboardHeightChange((res) => {
      this.keyHei = res.height
    })
    this.editorBoxPositionReset()
  },
  methods: {
    //编辑器初始化完成时触发
    onEditorReady() {
      uni.createSelectorQuery().in(this)
        .select('#seeker-editor')
        .context((res) => {
          this.editorCtx = res.context
          let rtTxt = this.value
          this.setContents(rtTxt) //设置富文本内容
        })
        .exec()
    },
    //设置富文本内容
    setContents(richText) {
      this.editorCtx.setContents({
        html: richText,
        success: (res) => {},
      })
    },
    //编辑器聚焦时触发
    bindFocus(res) {
      this.focus = true
      this.retracted = false
      this.$emit('bindfocus', {
        detail: {
          value: res,
        },
      })
    },
    //编辑器失去焦点时触发
    bindBlur(res) {
      this.focus = false
      this.$emit('bindblur', {
        detail: {
          value: res,
        },
      })
    },
    // 操作栏点击
    handleBarClick(item) {
      this.focus = true
      const { format, id } = item
      if (id == 3) {
        this.editorCtx.undo()
        this.$emit('last')
        return
      }
      if (id == 4) {
        this.editorCtx.redo()
        this.$emit('next')
        return
      }
      if (id == 2) {
        this.insertImage()
        return
      }
      if (format) {
        const { key, val } = format
        this.editorCtx.format(key, val)
      }
    },
    // 点击底部输入栏
    handleBarInputClick() {
      this.retracted = false
    },
    //清空编辑器内容
    clearContent() {
      this.editorCtx.clear({
        success: (res) => {
          this.showM = false
          this.$emit('clearSuccess')
        },
      })
    },
    // 设置样式
    formatStyle(item) {
      const { key, val } = item
      this.editorCtx.format(key, val)
    },
    // 通过 Context 方法改变编辑器内样式时触发，返回选区已设置的样式
    onStatusChange(res) {
      const formats = res.detail
      this.formats = formats
    },
    //编辑器输入中时触发
    bindInput(res) {
      const { html, text } = res.detail
      this.inputFakeText = text === '\n' ? '' : text
      this.$emit('input', html)
    },
    //撤销
    undo() {
      this.editorCtx.undo()
      this.$emit('undo')
    },
    //恢复
    redo() {
      this.editorCtx.redo()
      this.$emit('restore')
    },
    // 插入图片
    insertImage(img) {
      uni.chooseImage({
        count: 1,
        success: (res) => {
          this.editorCtx.insertImage({
            src: res.tempFilePaths[0],
            alt: '图像',
            success: function () {
              console.log('insert image success')
            },
          })
        },
      })
    },
    // 点击底板，关闭editor聚焦
    handleClickMask(e) {
      // 收起键盘但能够点击底板，说明editor仍居中聚焦未收起，需要手动复原
      if (!this.keyHei) {
        this.editorBoxPositionReset()
      }
      this.focus = false
      this.retracted = true
    },
    // 编辑器位置复原
    // 未聚焦的 box 是 static 的，这个方法赋予的 bottom 可以控制聚焦动画，本身没有定位作用
    editorBoxPositionReset() {
      uni.createSelectorQuery().in(this)
        .select('.editor-box')
        .boundingClientRect((data) => {
          console.log('editor-box data', data)
          const { height } = data
          this.editorBottom = this.windowHeight - height
        })
        .exec()
    },
  },
  computed: {
    barListActive() {
      return this.barList.map((item) => {
        if (item.format) {
          const { key, val } = item.format
          const isFormat = this.formats[key] == val
          if (item.text) {
            const activeColor = isFormat ? item.colorAct : item.color
            return {
              ...item,
              activeColor,
            }
          } else {
            const activeIcon = isFormat ? item.iconAct : item.icon
            return {
              ...item,
              activeIcon,
            }
          }
        }
        return {
          ...item,
          activeIcon: item.icon,
        }
      })
    },
  },
  watch: {
    keyHei(val) {
      console.log('keyHei change!', val)
      if (val) {
        // 键盘唤起，控制 bottom 紧贴
        this.editorBottom = val
      } else {
        if (!this.retracted) {
          // 键盘收起但编辑器未收起
          return
        } else {
          this.editorBoxPositionReset()
        }
      }
    },
    formats(val) {
      console.log('formats change!', val)
    },
    editorBottom(val) {
      console.log('editorBottom change!', val)
    },
  },
}
</script>

<style lang="scss" scoped>
.editor-container {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  .editor-box {
    position: absolute;
    z-index: 100;
    left: 0;
    right: 0;
    padding: 20rpx;
    border-radius: 20rpx 20rpx 0 0;
    background: #ddd;
    transition: 0.6s;
    .edit-body {
      background: #eee;
      margin: 10rpx;
      padding: 20rpx;
      border-radius: 20rpx;
      min-height: 300rpx;
    }
    .ql-container {
      height: auto;
    }
    .edit-bar {
      display: flex;
      justify-content: space-around;
      align-items: center;
      > view {
        padding: 10rpx;
        img {
          width: 40rpx;
          height: 40rpx;
        }
        span {
          font-size: 28rpx;
          width: 40rpx;
          line-height: 40rpx;
        }
      }
    }
  }
  .editor-mask {
    position: absolute;
    z-index: 90;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(0, 0, 0, 0.2);
  }
}
.editor-container-retracted {
  position: static;
  .editor-box {
    position: static;
  }
  .editor-mask {
    display: none;
  }
}
</style>
